package org.cos.generation.util.predict;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
import java.util.Set;

/**
 * The set which present as the relation of other set.
 * Such as UNION, INTERSECTION, PLUS, MINUS.
 * @author ZXD
 *
 */

public class UnionPredictSet implements PredictSet{
	
	/** The child sets of the compound set. */
	private List<PredictSet> childs = new LinkedList<PredictSet>();
	
	/**
	 * Constructor with nothing, which construct a all possible set.
	 */
	public UnionPredictSet() {
	}
	
	/**
	 * Get the child sets.
	 * @return
	 */
	public List<PredictSet> getChilds() {
		return childs;
	}

	/**
	 * Add the child set.
	 * @param child
	 * @return
	 */
	public void addChild(PredictSet child) {
		childs.add(child);
	}

	/**
	 * Present the set as string which outputted for test.
	 * This method traverses it's non-duplicated all descendants.  
	 */
	public String toString() {
		String str = "";
		if (childs.size() == 0) {
			str += "ALL";
		} else {
			Queue<PredictSet> setQueue = new LinkedList<PredictSet>();
			Set<PredictSet> setSet = new HashSet<PredictSet>();
			setQueue.add(this);
			setSet.add(this);
			while (setQueue.size() > 0) {
				PredictSet possSet = setQueue.poll();
				setSet.add(possSet);
				if (possSet.isAll()) {
					return "ALL";
				} else {
					if (possSet instanceof UnionPredictSet) {
						UnionPredictSet comp = (UnionPredictSet)possSet;
						for (PredictSet p : comp.childs) {
							if (!setSet.contains(p)) {
								setQueue.add(p);
							}
						}
					} else {
						str += possSet.toString();
						str += ",";
					}
				}
			}
			if (str.length() == 0) {
				return "ALL";
			} else {
				str = str.substring(0, str.length() - 1);
			}
		}
		return str;
	}

	public boolean isAll() {
		Queue<PredictSet> setQueue = new LinkedList<PredictSet>();
		Set<PredictSet> setSet = new HashSet<PredictSet>();
		setQueue.add(this);
		setSet.add(this);
		while (setQueue.size() > 0) {
			PredictSet possSet = setQueue.poll();
			setSet.add(possSet);
			if (possSet == null) {
				return true;
			} else {
				if (possSet instanceof UnionPredictSet) {
					UnionPredictSet comp = (UnionPredictSet)possSet;
					for (PredictSet p : comp.childs) {
						if (!setSet.contains(p)) {
							setQueue.add(p);
						}
					}
				} else {
					if (possSet.isAll()) return true;
				}
			}
		}
		return false;
		
	}
	
	public SetType getType() {
		return SetType.UNION;
	}

	public PredictSet getSet() {
		if (!isAll()) {
			UnionPredictSet retSet = new UnionPredictSet(); 
			
			Queue<PredictSet> setQueue = new LinkedList<PredictSet>();
			Set<PredictSet> setSet = new HashSet<PredictSet>();
			setQueue.add(this);
			setSet.add(this);
			while (setQueue.size() > 0) {
				PredictSet possSet = setQueue.poll();
				setSet.add(possSet);
				switch (possSet.getType()) {
				case UNION:
					UnionPredictSet unionSet = (UnionPredictSet)possSet;
					for (PredictSet p : unionSet.childs) {
						if (!setSet.contains(p)) {
							setQueue.add(p);
						}
					}
					break;
				case EQUAL:
					EqualPredictSet equalSet = (EqualPredictSet)possSet;
					if (!retSet.contains(equalSet.getValue())) {
						retSet.addChild(equalSet);
					}
					break;
				}
			}
			
			return retSet;
		}
		return null;
	}

	public boolean contains(Object o) {
		for (PredictSet child : childs) {
			if (child.contains(o)) return true;
		}
		return false;
	}
}
